home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / str.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  11.9 KB  |  578 lines

  1. /* 
  2.  * str.c--
  3.  *
  4.  *    String manipulation facilities for the Jaquith server.
  5.  *
  6.  * Copyright 1992 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/str.c,v 1.0 91/01/07 18:02:37 mottsmth Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include "jaquith.h"
  21.  
  22.  
  23. /*
  24.  *----------------------------------------------------------------------
  25.  *
  26.  * Str_Match --
  27.  *
  28.  *    See if a particular string matches a particular pattern.
  29.  *
  30.  * Results:
  31.  *    The return value is 1 if string matches pattern, and
  32.  *    0 otherwise.  The matching operation permits the following
  33.  *    special characters in the pattern: *?\[] (see the manual
  34.  *    entry for details on what these mean).
  35.  *
  36.  * Side effects:
  37.  *    None.
  38.  *
  39.  * Note: This wass stolen straight from the tcl distribution,
  40.  *       where it's called Tcl_StringMatch. Then curly support was added
  41.  *
  42.  *----------------------------------------------------------------------
  43.  */
  44.  
  45. int
  46. Str_Match(string, pattern)
  47.     register char *string;    /* String. */
  48.     register char *pattern;    /* Pattern, which may contain
  49.                  * special characters. */
  50. {
  51.     char c2;
  52.  
  53.     while (1) {
  54.     /* See if we're at the end of both the pattern and the string.
  55.      * If so, we succeeded.  If we're at the end of the pattern
  56.      * but not at the end of the string, we failed.
  57.      */
  58.     
  59.     if (*pattern == 0) {
  60.         if (*string == 0) {
  61.         return 1;
  62.         } else {
  63.         return 0;
  64.         }
  65.     }
  66.     if ((*string == 0) && (*pattern != '*')) {
  67.         return 0;
  68.     }
  69.  
  70.     /* If the next pattern character is '{', match any item
  71.      * in the set until the next '}'.
  72.      */
  73.     
  74.     if (*pattern == '{') {
  75.         int patLen;
  76.         int remLen;
  77.         int curlyDepth;
  78.         char *recursePat;
  79.         int recurseLen = 0;
  80.         char *endPat;
  81.         char *lastCurly;
  82.  
  83.         curlyDepth = 0;
  84.         for (lastCurly=pattern; *lastCurly != '\0'; lastCurly++) {
  85.         if (*lastCurly == '\\') {
  86.             lastCurly++;
  87.         } else if (*lastCurly == '{') {
  88.             curlyDepth++;
  89.         } else if ((*lastCurly == '}') && (--curlyDepth < 1)) {
  90.             break;
  91.         }
  92.         }
  93.         if (curlyDepth != 0) {
  94.         return 0;
  95.         }
  96.         remLen = strlen(lastCurly);
  97.         recurseLen = 1024;
  98.         recursePat = (char *)MEM_ALLOC("Str_Match",recurseLen*sizeof(char));
  99.         for (endPat= ++pattern; endPat <= lastCurly; endPat++) {
  100.         if (*endPat == '\\') {
  101.             endPat++;
  102.         } else if (*endPat == '{') {
  103.             curlyDepth++;
  104.         } else if ((*endPat == '}') && (curlyDepth > 0)) {
  105.             curlyDepth--;
  106.         } else if (((*endPat == '}') || (*endPat == ',')) &&
  107.                (curlyDepth == 0)) {
  108.             patLen = endPat-pattern;
  109.             if ((patLen+remLen) > recurseLen) {
  110.             MEM_FREE("Str_Match", recursePat);
  111.             recurseLen = patLen + remLen;
  112.             recursePat = (char *)MEM_ALLOC("Str_Match",
  113.                               recurseLen*sizeof(char));
  114.             }
  115.             strncpy(recursePat, pattern, patLen);
  116.             strcpy(recursePat+patLen, lastCurly+1);
  117.             if (Str_Match(string, recursePat)) {
  118.             MEM_FREE("Str_Match", recursePat);
  119.             return 1;
  120.             }
  121.             pattern = endPat+1;
  122.         }
  123.         }
  124.         MEM_FREE("Str_Match", recursePat);
  125.     }
  126.  
  127.     /* Check for a "*" as the next pattern character.  It matches
  128.      * any substring.  We handle this by calling ourselves
  129.      * recursively for each postfix of string, until either we
  130.      * match or we reach the end of the string.
  131.      */
  132.     
  133.     if (*pattern == '*') {
  134.         pattern += 1;
  135.         if (*pattern == 0) {
  136.         return 1;
  137.         }
  138.         while (*string != 0) {
  139.         if (Str_Match(string, pattern)) {
  140.             return 1;
  141.         }
  142.         string += 1;
  143.         }
  144.         return 0;
  145.     }
  146.     
  147.     /* Check for a "?" as the next pattern character.  It matches
  148.      * any single character.
  149.      */
  150.  
  151.     if (*pattern == '?') {
  152.         goto thisCharOK;
  153.     }
  154.  
  155.     /* Check for a "[" as the next pattern character.  It is followed
  156.      * by a list of characters that are acceptable, or by a range
  157.      * (two characters separated by "-").
  158.      */
  159.     
  160.     if (*pattern == '[') {
  161.         pattern += 1;
  162.         while (1) {
  163.         if ((*pattern == ']') || (*pattern == 0)) {
  164.             return 0;
  165.         }
  166.         if (*pattern == *string) {
  167.             break;
  168.         }
  169.         if (pattern[1] == '-') {
  170.             c2 = pattern[2];
  171.             if (c2 == 0) {
  172.             return 0;
  173.             }
  174.             if ((*pattern <= *string) && (c2 >= *string)) {
  175.             break;
  176.             }
  177.             if ((*pattern >= *string) && (c2 <= *string)) {
  178.             break;
  179.             }
  180.             pattern += 2;
  181.         }
  182.         pattern += 1;
  183.         }
  184.         while ((*pattern != ']') && (*pattern != 0)) {
  185.         pattern += 1;
  186.         }
  187.         goto thisCharOK;
  188.     }
  189.     
  190.     /* If the next pattern character is '\', just strip off the '\'
  191.      * so we do exact matching on the character that follows.
  192.      */
  193.     
  194.     if (*pattern == '\\') {
  195.         pattern += 1;
  196.         if (*pattern == 0) {
  197.         return 0;
  198.         }
  199.     }
  200.  
  201.     /* There's no special character.  Just make sure that the next
  202.      * characters of each string match.
  203.      */
  204.     
  205.     if (*pattern != *string) {
  206.         return 0;
  207.     }
  208.  
  209.     thisCharOK: pattern += 1;
  210.     string += 1;
  211.     }
  212. }
  213.  
  214.  
  215.  
  216. /*
  217.  *----------------------------------------------------------------------
  218.  *
  219.  * Str_Split --
  220.  *
  221.  *    Split a string into parts.
  222.  *
  223.  * Results:
  224.  *      Array of parts and number of parts.
  225.  *
  226.  * Side effects:
  227.  *    none.
  228.  *
  229.  * Note:
  230.  *      Parts is parts. List is NULL terminated.
  231.  *
  232.  *----------------------------------------------------------------------
  233.  */
  234.  
  235. char **
  236. Str_Split(pathArg, splitChar, partCntPtr, elide, insidePtr)
  237.     char *pathArg;            /* pathname to parse */
  238.     char splitChar;           /* separator */
  239.     int *partCntPtr;          /* number of components */
  240.     int elide;                /* 1 == merge multiple split chars */
  241.     char **insidePtr;         /* ptr to interior space */
  242. {
  243.     char *src;
  244.     char *path;
  245.     int copying;
  246.     int partCnt;
  247.     char **workParts;
  248.     char *start = NULL;
  249.  
  250.     *insidePtr = path = (char *)MEM_ALLOC("Str_Split",
  251.                       (strlen(pathArg)+1)*sizeof(char));
  252.     strcpy(path, pathArg);
  253.  
  254.     for (src=path,partCnt=0,copying=0,start=NULL; *src; src++) {
  255.     if (*src == splitChar) {
  256.         if ((copying) || (!elide)) {
  257.         copying = 0;
  258.         partCnt++;
  259.         }
  260.     } else {
  261.         if (!copying) {
  262.         copying = 1;
  263.         }
  264.     }
  265.     }
  266.     if ((copying) || (!elide)) {
  267.     partCnt++;
  268.     }
  269.  
  270.     workParts = (char **)MEM_ALLOC("Str_Split", (partCnt+1)*sizeof(char *));
  271.  
  272.     for (src=path,partCnt=0,copying=0,start=NULL; *src; src++) {
  273.     if (*src == splitChar) {
  274.         if ((copying) || (!elide)) {
  275.         copying = 0;
  276.         if (start) {
  277.             workParts[partCnt++] = start;
  278.             start = NULL;
  279.         } else {
  280.             workParts[partCnt++] = src;
  281.         }
  282.         *src = '\0';
  283.         }
  284.     } else {
  285.         if (!copying) {
  286.         start = src;
  287.         copying = 1;
  288.         }
  289.     }
  290.     }
  291.     if ((copying) || (!elide)) {
  292.     if (start) {
  293.         workParts[partCnt++] = start;
  294.     } else {
  295.         workParts[partCnt++] = src;
  296.     }
  297.     }
  298.  
  299.     workParts[partCnt] = NULL;
  300.     *partCntPtr = partCnt;
  301.  
  302.     return workParts;
  303.  
  304. }
  305.  
  306.  
  307. /*
  308.  *----------------------------------------------------------------------
  309.  *
  310.  * Str_Unquote --
  311.  *
  312.  *    Remove '\' preceding metacharacters in string
  313.  *
  314.  * Results:
  315.  *    New string with '\' inserted.
  316.  *
  317.  * Side effects:
  318.  *    none.
  319.  *
  320.  *----------------------------------------------------------------------
  321.  */
  322.  
  323. int
  324. Str_Unquote(src)
  325.     char *src;                /* string to be quoted */
  326. {
  327.     char *dest;
  328.     char *ptr;
  329.  
  330.     for (ptr=src,dest=src; *ptr; ptr++,dest++) {
  331.     if (*ptr == '\\') {
  332.         ptr++;
  333.     }
  334.     *dest = *ptr;
  335.     }
  336.     *dest = '\0';
  337.  
  338.     return T_SUCCESS;
  339.  
  340. }
  341.  
  342.  
  343. /*
  344.  *----------------------------------------------------------------------
  345.  *
  346.  * Str_Quote --
  347.  *
  348.  *    Quote metacharacters in string
  349.  *
  350.  * Results:
  351.  *    Updates string in place.
  352.  *
  353.  * Side effects:
  354.  *    none.
  355.  *
  356.  *----------------------------------------------------------------------
  357.  */
  358.  
  359.  
  360. char *
  361. Str_Quote(src, metachars)
  362.     char *src;                /* string to be quoted */
  363.     char *metachars;          /* list of chars to be quoted */
  364. {
  365.     int len;
  366.     char *newPtr;
  367.     char *ptr;
  368.  
  369.     for (ptr=src,len=0; *ptr; ptr++,len++) {
  370.     if (STRCHR(metachars, *ptr) != NULL) {
  371.         len++;
  372.     }
  373.     }
  374.  
  375.     newPtr = MEM_ALLOC("Str_Quote", (len+1)*sizeof(char));
  376.  
  377.     for (ptr=src,len=0; *ptr; ptr++,len++) {
  378.     if (STRCHR(metachars, *ptr) != NULL) {
  379.         *(newPtr+len++) = '\\';
  380.     }
  381.     *(newPtr+len) = *ptr;
  382.     }
  383.     *(newPtr+len) = '\0';
  384.  
  385.     return newPtr;
  386.  
  387. }
  388.  
  389.  
  390.  
  391. /*
  392.  *----------------------------------------------------------------------
  393.  *
  394.  * Str_StripDots
  395.  *
  396.  *    Remove '.' and '..' references in path;
  397.  *
  398.  * Results:
  399.  *    none.
  400.  *
  401.  * Side effects:
  402.  *    none.
  403.  *
  404.  *----------------------------------------------------------------------
  405.  */
  406.  
  407. int
  408. Str_StripDots(src)
  409.     char *src;                /* pathname to be updated in place */
  410. {
  411.     register char *path = src;
  412.     register char *work = src;
  413.     char *work1;
  414.     char *work2;
  415.     char *work3;
  416.  
  417.     while (*work) {
  418.     while (*work == '/') {
  419.         work1 = work+1;
  420.         work2 = work+2;
  421.         work3 = work+3;
  422.         if ((*work == '/') && (*work1 == '.') &&
  423.         ((*work2 == '/') || (*work2 == '\0'))) {
  424.         work = work2;
  425.         } else if ((*work == '/') &&
  426.                (*work1 == '.') && (*work2 == '.') &&
  427.                ((*work3 == '/') || (*work3 == '\0'))) {
  428.         while ((*--path != '/') && (path >= src)) {
  429.             ;
  430.         }
  431.         if (path >= src) {
  432.             work = work3;
  433.         } else {
  434.             fprintf(stderr,"bad path: %s\n", src);
  435.             return T_FAILURE;
  436.         }
  437.         } else {
  438.         break;
  439.         }
  440.     }
  441.     *path++ = *work++;
  442.     } 
  443.     *path = '\0';
  444.     return T_SUCCESS;
  445. }
  446.  
  447.  
  448. /*
  449.  *----------------------------------------------------------------------
  450.  *
  451.  * Str_Dup --
  452.  *
  453.  *    Safe string duplicator.
  454.  *
  455.  * Results:
  456.  *    Copy of string made using our allocator.
  457.  *
  458.  * Side effects:
  459.  *    None.
  460.  *
  461.  *----------------------------------------------------------------------
  462.  */
  463.  
  464. char *
  465. Str_Dup(string)
  466.     char *string;             /* string to be duplicated */
  467. {
  468.     char *newString;
  469.  
  470.     newString = (char *)MEM_ALLOC("Str_Dup",
  471.                   (strlen(string)+1)*sizeof(char));
  472.     strcpy(newString, string);
  473.     return newString;
  474.  
  475. }
  476.  
  477.  
  478. /*
  479.  *----------------------------------------------------------------------
  480.  *
  481.  * Str_Cat --
  482.  *
  483.  *    Safe string concatenator.
  484.  *
  485.  * Results:
  486.  *    Concatenation of string parts made using our allocator.
  487.  *
  488.  * Side effects:
  489.  *    None.
  490.  *
  491.  * Notes:
  492.  *      Argument list is: argument count, strings to be concatenated.
  493.  *
  494.  *----------------------------------------------------------------------
  495.  */
  496.  
  497. char *
  498. Str_Cat(va_alist)
  499.     va_dcl
  500. {
  501.     int argCnt;
  502.     int len;
  503.     va_list argPtr;
  504.     char *curPtr;
  505.     char *bufPtr;
  506.     char *curArg;
  507.     int i;
  508.  
  509.     va_start(argPtr);
  510.     argCnt = va_arg(argPtr, int);
  511.     for (i=0,len=0; i<argCnt; i++) {
  512.     curArg = va_arg(argPtr, char *);
  513.     len += strlen(curArg);
  514.     }
  515.     va_end(argPtr);
  516.  
  517.     bufPtr = MEM_ALLOC("Str_Cat", (len+1)*sizeof(char));
  518.  
  519.     va_start(argPtr);
  520.     argCnt = va_arg(argPtr, int);
  521.     for (i=0,curPtr=bufPtr; i<argCnt; i++) {
  522.     curArg = va_arg(argPtr, char *);
  523.     while (*curArg) {
  524.         *curPtr++ = *curArg++;
  525.     } 
  526.     }
  527.     va_end(argPtr);
  528.  
  529.     *(bufPtr+len) = '\0';
  530.     return bufPtr;
  531.  
  532. }
  533.  
  534. #ifndef HASSTRTOK
  535.  
  536. /*
  537.  *----------------------------------------------------------------------
  538.  *
  539.  * strtok --
  540.  *
  541.  *      Split a string up into tokens
  542.  *
  543.  * Results:
  544.  *      If the first argument is non-NULL then a pointer to the
  545.  *      first token in the string is returned.  Otherwise the
  546.  *      next token of the previous string is returned.  If there
  547.  *      are no more tokens, NULL is returned.
  548.  *
  549.  * Side effects:
  550.  *      Overwrites the delimiting character at the end of each token
  551.  *      with '\0'.
  552.  *
  553.  *----------------------------------------------------------------------
  554.  */
  555.  
  556. char *
  557. strtok(s, delim)
  558.     char *s;            /* string to search for tokens */
  559.     const char *delim;  /* delimiting characters */
  560. {
  561.     static char *lasts;
  562.     register int ch;
  563.  
  564.     if (s == 0)
  565.         s = lasts;
  566.     do {
  567.         if ((ch = *s++) == '\0')
  568.             return 0;
  569.     } while (STRCHR(delim, ch));
  570.     --s;
  571.     lasts = s + strcspn(s, delim);
  572.     if (*lasts != 0)
  573.         *lasts++ = 0;
  574.     return s;
  575. }
  576.  
  577. #endif
  578.